package com.ogawa.base.mqtt

import android.text.TextUtils
import com.blankj.utilcode.util.LogUtils
import com.google.gson.Gson
import com.jeremyliao.liveeventbus.LiveEventBus
import com.ogawa.base.Constant.CommmandNum
import com.ogawa.base.Constant.MqttConstant
import com.ogawa.base.Constant.MqttConstant.LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE
import com.ogawa.base.Constant.MqttConstant.LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE
import com.ogawa.base.Constant.MqttConstant.MQTT_STATE_CONNECTED
import com.ogawa.base.Constant.MqttConstant.MQTT_STATE_CONNECTING
import com.ogawa.base.Constant.MqttConstant.MQTT_STATE_UNCONNECT
import com.ogawa.base.bean.PublishBean
import com.ogawa.base.bean.ReceiveMassageBean
import com.ogawa.base.utils.NetUtil
import com.ogawa.base.utils.NetUtil.Companion.instance
import com.ska.skautils.utilcode.util.SkaUtils
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit

class MqttManager private constructor() {
    private val TAG = "MqttManager_TAG"
    private var mqttAndroidClient: MqttAndroidClient? = null
    private var clientId //自定义
            : String? = null
    private var pool: ScheduledExecutorService? = null
    private var mqttConnectOptions: MqttConnectOptions? = null
    private var reconnectPool : ScheduledExecutorService? = null//重连线程池
    var curSn: String? = null
    private lateinit var  mGson: Gson
    private var mqttAccount: String? = null
    private var mqttPsw: String? = null
    private var reCount = 0
    private var isSoftAp = false
    companion object{
        val instance = MqttManager()
    }

     fun  setIsSoftAp(isSoft :Boolean){
        isSoftAp = isSoft
    }

    /**
     * 是否连接
     *
     * @return
     */
    val isConnect: Boolean
        get() {
            if (!NetUtil.instance.hasNet()) {
                return false
            }
            else{
                mqttAndroidClient?.let {
                    return  it.isConnected
                }?:let {
                  return  false
                }
            }
        }

    fun buildClient() {
        LiveEventBus.get(LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE).post(MQTT_STATE_CONNECTING)
        closeMQTTAndReconnect() //先关闭上一个连接
        buildMQTTClient()
    }

    private fun buildMQTTClient() {
        clientId = "android" + ((Math.random() * 9 + 1) * 10000).toInt()
        mqttAndroidClient = MqttAndroidClient(SkaUtils.getContext(), MqttConstant.HOST, clientId)
        mqttAndroidClient?.setCallback(mqttCallback)
        mqttConnectOptions = MqttConnectOptions()
        mqttConnectOptions?.connectionTimeout = 10
        mqttConnectOptions?.keepAliveInterval = 20
        mqttConnectOptions?.isCleanSession = true
        mGson = Gson()
        doClientConnection()
    }

    private val iMqttActionListener: IMqttActionListener = object : IMqttActionListener {
        override fun onSuccess(asyncActionToken: IMqttToken) {
            LogUtils.i(TAG + "connect-" + "onSuccess")
            closeReconnectTask()
            isReconnect = false
            reCount = 0
            subscribeToTopic()
        }

        override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
            //connect-onFailure-MqttException (0) - java.net.UnknownHostException
            LogUtils.i(TAG + "connect-" + "onFailure-" + exception.message)
            startReconnectTask("onFailure")
        }
    }
    private val mqttCallback: MqttCallback = object : MqttCallback {
        override fun connectionLost(cause: Throwable) {
            LogUtils.i(TAG + "close-" + "connectionLost-" + cause)
            startReconnectTask("connectionLost")
        }

        override fun messageArrived(topic: String, message: MqttMessage) {
            LogUtils.i("messageArrived-$topic")
            val bean = ReceiveMassageBean()
            bean.topic = topic
            bean.message = message
            LiveEventBus.get(LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE).post(bean)
        }

        override fun deliveryComplete(token: IMqttDeliveryToken) {
            try {
                LogUtils.i(TAG + "deliveryComplete-" + token.message.toString())
            } catch (e: MqttException) {
                e.printStackTrace()
            }
        }
    }

    fun setMqttMsg(mqttAccount: String?, mqttPsw: String?) {
        this.mqttAccount = mqttAccount
        this.mqttPsw = mqttPsw
    }

    var isReconnect = false
    private fun startReconnectTask(from: String) {
        if (isReconnect) {
            return
        }
        isReconnect = true
        LogUtils.e("$TAG==FromWherer===$from")
        reconnectPool = Executors.newSingleThreadScheduledExecutor()
        reconnectPool?.scheduleAtFixedRate(Runnable {
            if (reCount > 5) {
                LogUtils.e("disconnecggg" + "==startReconnectTask=reconnectPool")
                LiveEventBus.get(LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE).post(MQTT_STATE_UNCONNECT)
                reconnectPool?.shutdownNow()
                isReconnect = false
                reCount = 0
            }
            else{
                reCount++
                LogUtils.e("$TAG==startReconnectTask=$reCount")
                closeMQTT()
                LiveEventBus.get(LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE).post(MQTT_STATE_CONNECTING)
                buildMQTTClient()
            }

        }, 0, 2000, TimeUnit.MILLISECONDS)
    }

    @Synchronized
    private fun closeReconnectTask() {
        if (reconnectPool != null) {
            reconnectPool?.shutdownNow()
            reconnectPool = null
        }
    }

    /**
     * 连接MQTT服务器
     */
    @Synchronized
    private fun doClientConnection() {
        if (TextUtils.isEmpty(mqttAccount) || TextUtils.isEmpty(mqttPsw)) {
            LogUtils.e(TAG + "账号密码空退出")
            return
        }
        mqttConnectOptions?.userName = mqttAccount
        mqttConnectOptions?.password = mqttPsw?.toCharArray()
        pool = Executors.newScheduledThreadPool(1)
        pool?.execute(Runnable {
            try {
                mqttAndroidClient?.connect(mqttConnectOptions, null, iMqttActionListener)
            } catch (e: MqttException) {
                e.printStackTrace()
            }
        })
    }

    private fun subscribeToTopic() { //订阅之前会取消订阅，避免重连导致重复订阅
        try {
            val registerTopic = "cmd/up/$curSn" //自定义
            val controlTopic = "cmd/back/$curSn/$clientId" //自定义
            val topicFilter = arrayOf(registerTopic, controlTopic)
            val qos = intArrayOf(2, 2)
            mqttAndroidClient?.unsubscribe(topicFilter, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) {
                    LogUtils.i(TAG + "unsubscribe-" + "success")
                }

                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
                    LogUtils.i(TAG + "unsubscribe-" + "failed-" + exception)
                }
            })
            mqttAndroidClient?.subscribe(topicFilter, qos, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) { //订阅成功
                    LogUtils.e(TAG + "订阅主题成功")
                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE).post(MQTT_STATE_CONNECTED)
                    //                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_STATUS, Boolean.class).post(true);
//                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE2).post(LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE2);
                    publish(CommmandNum.mStatusRunning, "")
                    publish(CommmandNum.mAllStatusQuery, "00")
                }

                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
//                    startReconnectTask();
                    LogUtils.e("disconnecggg" + "==startReconnectTask=onFailure")
                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_MQTT_CONNECT_STATE).post(MQTT_STATE_UNCONNECT)
                }
            })
        } catch (ex: MqttException) {
        }
    }

    private fun publish(topic: String, qos: Int, content: String) {
        if (mqttAndroidClient == null) return
        val message = MqttMessage(content.toByteArray())
        message.qos = qos
        try {
            LogUtils.e(TAG + "发送：" + topic + " : " + qos + " : " + content)
            mqttAndroidClient?.publish(topic, message, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) {
//                    TVLog.i("sendMQTT-"+"success:" + msg);
                }

                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
//                    startReconnectTask();
                    LogUtils.i(TAG + "sendMQTT-" + "failed:")
                }
            })
        } catch (e: MqttException) {
            e.printStackTrace()
        }
    }
    /**
     * 发布消息,带附加值
     *
     * @param func
     * @param model
     */
    /**
     * 发布消息，不带附加值
     *
     * @param func
     * @param model
     */
    @JvmOverloads
    fun publish(func: String?, model: String?, addition: String? = null) {
        LogUtils.e("sendCommondFinal:code=$func==model=$model==addition=$addition")
        val bean = PublishBean()
        bean.functionCode = func
        bean.modelValue = model
        bean.clientId = clientId
        bean.sn = curSn
        bean.additionalValue = addition
        publish("cmd/down/$curSn", 2, mGson.toJson(bean))
    }

    fun clearData() {
        reCount = 0
        closeMQTTAndReconnect()
    }

    fun closeMQTT() {
        LogUtils.i(TAG + "closeMQTT-" +"_---"+ (mqttAndroidClient == null))
        mqttAndroidClient?.let {
            try {
                it.unregisterResources()
                it.setCallback(null)
                it.disconnect()
                LogUtils.i(TAG + "closeMQTT-" + it.clientId)
                mqttAndroidClient = null
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

    }

    fun closeMQTTAndReconnect() {
        closeReconnectTask()
        closeMQTT()
    }


}